package com.metagurukul.metagranth.service;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;


import com.metagurukul.metagranth.exception.MetaSqlException;
import com.metagurukul.metagranth.model.common.connection.ConnectionPoolFactory;
import com.metagurukul.metagranth.model.dao.AnswerDAO;
import com.metagurukul.metagranth.model.dao.QuestionDAO;
import com.metagurukul.metagranth.model.dao.QuestionTagMappingDAO;
import com.metagurukul.metagranth.model.dao.TagDAO;
import com.metagurukul.metagranth.model.dao.UserDAO;
import com.metagurukul.metagranth.util.Validator;
import com.metagurukul.metagranth.vo.Answer;
import com.metagurukul.metagranth.vo.AnswerMetaData;
import com.metagurukul.metagranth.vo.MetaData;
import com.metagurukul.metagranth.vo.Question;
import com.metagurukul.metagranth.vo.QuestionTagMapping;
import com.metagurukul.metagranth.vo.Tag;

/**
 * This class handles all the operations performed by QuestionDAO
 * @author Team MetaGranth
 */

public class QuestionService {

	private final static int NUMBER_OF_QUESTION = 15;

	/**
	 * This method saves the question, tags, and question tag mapping in database
	 * @param Question question
	 * @param Tag tag
	 * @return int status
	 * @throws Exception
	 */
	
	public static int askQuestion(Question question, Tag tag) throws Exception {
		int status = 0;
		try {// checking question and tags whether these are null or not
			if ((!Validator.isNull(question)) && (!Validator.isNull(tag))) {
				int questionId = QuestionDAO.save(question);
				String[] tagNames = tag.getTagName().split(",");
				Tag tempTag = new Tag();
				QuestionTagMapping questionTagMapping = new QuestionTagMapping();

				for (int i = 0; i < tagNames.length; i++) {
					tempTag.setTagName(tagNames[i].trim());
					int inTagId=TagDAO.getTagIdByTagName(tempTag.getTagName().trim());
					if(inTagId==0){
						inTagId = TagDAO.save(tempTag);
					}
					questionTagMapping.setQuestionId(questionId);
					questionTagMapping.setTagId(inTagId);
					status = QuestionTagMappingDAO.save(questionTagMapping);
				}
			}
			
		} catch (MetaSqlException exception) {
			throw new SQLException(exception);
		}
		return status;
	}

	/**
	 * this function will call dao class to find latest 'number' of questions
	 * where 'number' is a constant which tells no of questions to retrieve. if
	 * any exception occurs that is throws which is handeled by action class.
	 * @return
	 * @throws Exception
	 **/
	public static ArrayList<MetaData> getLatestQuestions() throws Exception {
		try {
			ArrayList<Question> questionList = QuestionDAO.searchLatestQuestion(NUMBER_OF_QUESTION);
			return getMetaDataOfQuestions(questionList);
		} catch (Exception exception) {
			throw exception;
		}
	}
	
	/**
	 * This method retrieves the meta data of question
	 * @param ArrayList<Question>> questionList
	 * @return ArrayList<MetaData> metadatalist
	 * @throws Exception
	 */

	private static ArrayList<MetaData> getMetaDataOfQuestions(
			ArrayList<Question> questionList) throws Exception {
		try {
			ArrayList<MetaData> metadataList = new ArrayList<MetaData>();
			for (Question question : questionList) {

				metadataList.add(getMetaDataOfQuestion(question));
			}
			return metadataList;
		} catch (Exception exception) {
			throw exception;
		}
	}

	/**
	 * This method retrieves meta data of a single question
	 * @param Question question
	 * @return MetaData
	 * @throws Exception
	 */
	
	private static MetaData getMetaDataOfQuestion(Question question)
			throws Exception {
		try {
			MetaData metadata = new MetaData();
			metadata.setQuestion(question);
			
			int questionId = question.getQuesId();
			metadata.setTagList(TagDAO.getTagsByQuestionId(questionId));
			int userId = question.getUserId();
			metadata.setUser(UserDAO.getUserById(userId));
			
			ArrayList<Answer> answerList = AnswerDAO.getAnswerByQuestionId(questionId);
			ArrayList<AnswerMetaData> answerMetaDataList = new ArrayList<AnswerMetaData>();
			
			for (Answer answer : answerList) {
				AnswerMetaData answerMetaData = getMetaDataOfAnswer(answer);
				answerMetaDataList.add(answerMetaData);
			}
			
			metadata.setAnswerMetaDataList(answerMetaDataList);
			return metadata;
		} catch (Exception exception) {
			throw exception;
		}
	}

	/**
	 * This method gets the meta data of answer 
	 * @param answer
	 * @return
	 * @throws Exception
	 */
	
	private static AnswerMetaData getMetaDataOfAnswer(Answer answer)
			throws Exception {

		try {
			AnswerMetaData answerMetaData = new AnswerMetaData();
			answerMetaData.setAnswer(answer);
			int userId = answer.getUid();
			answerMetaData.setUser(UserDAO.getUserById(userId));

			return answerMetaData;
		} catch (Exception exception) {
			throw exception;
		}
	}

	/**
	 * This method searches the questions by question
	 * @param String byQuestion
	 * @return ArrayList<MetaData>
	 * @throws Exception
	 */
	
	public static ArrayList<MetaData> searchByQuestion(String byQuestion)
			throws Exception {
		try {
			return getMetaDataOfQuestions(QuestionDAO.searchByQuestion(byQuestion));
		} catch (Exception exception) {
			throw exception;
		}
	}

	/**
	 * This method searches questions by tags 
	 * @param query
	 * @return ArrayList<MetaData>
	 * @throws Exception
	 */
	
	public static ArrayList<MetaData> searchByTag(String query)
			throws Exception {
		ArrayList<Question> questionList = new ArrayList<Question>();
		String tagNames[] = query.split(",");

		try {
			// searching questions by each tag
			for (String tagName : tagNames) {
				Tag tagObject = new Tag();
				tagObject.setTagName(tagName.trim());
				QuestionDAO questionDaoObject = new QuestionDAO();
				
				// searching by tag
				ArrayList<Tag> tagList = TagDAO.searchByTag(tagObject);
				for (Tag tag : tagList) {
					questionList.addAll(questionDaoObject.searchByTag(tag));
				}
			}
			return getMetaDataOfQuestions(questionList);

		} catch (Exception exception) {
			throw exception;
		}
	}

	/**
	 * This method searches the questions by question and tags
	 * @param byQuestion
	 * @param byTag
	 * @return
	 * @throws Exception
	 */
	
	public static ArrayList<MetaData> searchByQuestionAndTag(String byQuestion,
			String byTag) throws Exception {
		try {
			ArrayList<MetaData> questionMetaDataList = searchByTag(byTag);
			questionMetaDataList.addAll(searchByQuestion(byQuestion));
			return questionMetaDataList;
		} catch (Exception exception) {
			throw exception;
		}
	}

	/**
	 * This method retrieves metadata of question by question id
	 * @param int questionId
	 * @return MetaData metaData
	 * @throws Exception
	 */
	
	public static MetaData getQuestionDetailByQuestionId(int questionId)
			throws Exception {

		try {
			Question question = QuestionDAO.searchQuestionbyId(questionId);
			MetaData metaData = getMetaDataOfQuestion(question);
			return metaData;
		} catch (Exception exception) {
			throw exception;
		}
	}

	/**
	 * This method gets Meta data of all the question 
	 * @return ArrayList<MetaData>
	 * @throws Exception
	 */
	
	public static ArrayList<MetaData> getAllQuestions() throws Exception {
		try {
			// calling Question DAO to get all the questions
			return getMetaDataOfQuestions(QuestionDAO.getAllQuestions());
		} catch (Exception exception) {
			throw exception;

		}
	}

	/**
	 * This method gets all the questions for admin to be approved   
	 * @return ArrayList<MetaData> Meta data of all the questions
	 * @throws Exception
	 */
	public static ArrayList<MetaData> getAllQuestionsForAdmin()
			throws Exception {
		ArrayList<Question> questionList = null;
		ArrayList<MetaData> metaDataList = null;
		try {
			questionList = QuestionDAO.getAllQuestionsForAdmin();
			metaDataList = getMetaDataOfQuestions(questionList);
			System.out.println(questionList.size());
		} catch (Exception exception) {

			throw exception;
		}
		return metaDataList;
	}
	
	
	/**
	 * THis method gets all the unanswered questions 
	 * @return ArrayList<MetaData>
	 * @throws Exception
	 */
	public static ArrayList<MetaData> getUnansweredQuestions() throws Exception {
		try {
			// calling QuestionDAO method to search unanswered questions
			ArrayList<Question> questionList = QuestionDAO.searchUnansweredQuestion();
			return getMetaDataOfQuestions(questionList);
		} catch (Exception exception) {
			throw exception;
		}
	}
	
	/**
	 * This method gets Title list of all the questions on the basis of key
	 * @param String key
	 * @return List<String> matched
	 * @throws Exception
	 */
	
	public static List<String> getQuestionTitleList(String key) throws Exception {
		ConnectionPoolFactory connectionPoolFactory = ConnectionPoolFactory.getInstance();
		
		// Getting all the questions
		ArrayList<Question> questionList = QuestionDAO.getAllQuestions();
		
		// Setting titles of all the questions in questionTitle
		List<String> questionTitle = new ArrayList<String>();
		for (Question question : questionList) {
			questionTitle.add(question.getTitle());
		}
		
		int tagListSize = questionTitle.size();
		String questionValue = null;
		key = key.toLowerCase();
		
		// variable matched contains all the titles of mached with key 
		List<String> matched = new ArrayList<String>();
		
		// matching all the titles with key
		for(int i=0; i<tagListSize; i++) {
			questionValue = questionTitle.get(i).toLowerCase();
			if(questionValue.startsWith(key)) {
				matched.add(questionTitle.get(i));
			}
		}
		return matched;
	}
	
	/**
	 * This method updates edited question
	 * @param Question questionObj
	 * @throws MetaSqlException 
	 */
	
	public static void updateEditedQuestion(Question questionObj) throws MetaSqlException{
		QuestionDAO.updateEditedQuestion(questionObj);
	}
	
	/**
	 * This method updates edited tags. This method receives tag list and question id and  updated tags related to that
	 * question and tag list.
	 * @param tagList
	 * @param questionId
	 * @throws MetaSqlException
	 */
	
	public static void updateEditedTags(String tagList, int questionId) throws MetaSqlException{
		// Getting different tags by spliting a tag list
		String[] tagNames = tagList.split(",");

		// new tag object is created for each tag and saved in tag list 
		Tag tempTag = new Tag();
		
		// Before starting update question tag mapping, previous mapping is deleted.
		QuestionTagMappingDAO.deleteRecordsByQid(questionId);
		
		// New mapping is contained by following variable
		QuestionTagMapping questionTagMapping = new QuestionTagMapping();

		// All the tags are saved 
		for (int count = 0; count < tagNames.length; count++) {
			tempTag.setTagName(tagNames[count].trim());
			int inTagId=TagDAO.getTagIdByTagName(tempTag.getTagName());
			if(inTagId==0){
				inTagId = TagDAO.save(tempTag);
			}
			// question tag mapping is updated
			questionTagMapping.setQuestionId(questionId);
			questionTagMapping.setTagId(inTagId);
			QuestionTagMappingDAO.save(questionTagMapping);
		}
	}
	
	/**
	 * This method returns all the editable questions
	 * @param int userId
	 * @return ArrayList<MetaData>
	 * @throws Exception
	 */
	
	public static ArrayList<MetaData> getEditableQuestions(int userId) throws Exception{
		// calling QuestionDAO method  to get editable question by userId
		ArrayList<Question> editableQuestions = QuestionDAO.getEditableQuestions(userId);
		return getMetaDataOfQuestions(editableQuestions);
	}
	
	/**
	 * This method returns question related to question id
	 * @param int qid
	 * @return Question
	 * @throws MetaSqlException 
	 */
	
	public static Question getQuestionById(int qid) throws MetaSqlException{
		// calling QuestionDAO to get Question related to question id
		return QuestionDAO.getQuestionbyId(qid);
	}

	
	
	/**
	 * This method gets meta data of all the questions by tag
	 * @param Tag tag
	 * @return ArrayList<MetaData>
	 * @throws Exception
	 */
	
	public static ArrayList<MetaData> searchByTag(Tag tag) throws Exception {	
		// this variable will contain all the questions searched byn tag
		ArrayList<Question> questionList = new ArrayList<Question>();
		try{		
		questionList.addAll(QuestionDAO.searchByTagObject(tag));
		return getMetaDataOfQuestions(questionList);
		}catch(Exception exception) {
			throw exception;
			
		}
		
	}
}
